package es.udc.empresauriostic.geofinder.model.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import es.udc.empresauriostic.geofinder.R;
import es.udc.empresauriostic.geofinder.model.Game;
import es.udc.empresauriostic.geofinder.model.GameGlobalStatus;
import es.udc.empresauriostic.geofinder.model.GameUserData;
import es.udc.empresauriostic.geofinder.model.Notification;

/**
 * Parsing utils.
 * 
 * @author Santiago Munín González
 * 
 */
public class Util {
	private static String NOTIFICATIONS_TAG = "notifications";
	private static String GAME_LIST_TAG = "games";
	private static String GAME_ID_TAG = "game_id";
	private static String GAME_LOCATION_TAG = "game_location";
	private static String GAME_NUMBER_OF_USERS_TAG = "game_n_users";
	private static String GAME_END_DATE_TAG = "game_end_date";
	private static String GAME_MAX_STEP_TAG = "game_max_step";
	private static String GAME_USERS_STATUS_TAG = "game_users_status";
	private static String USER_NAME_TAG = "username";
	private static String CURRENT_STEP_TAG = "current_step";
	private static String CURRENT_SCORE_TAG = "current_score";
	private static String HASH_ALGORITHM = "SHA-1";
	private static String USER_SCORE_TAG = "user_score";
	private static String HIGH_SCORES_TAG = "high_scores";

	/**
	 * Parses a game list in JSON format.
	 * 
	 * @param gameList
	 *            Game list in JSON format.
	 * @return {@link Game} list.
	 */
	public static List<Game> parseGameList(String gameList) {
		List<Game> result = new LinkedList<Game>();
		try {
			JSONObject json = new JSONObject(gameList);
			JSONArray games = json.getJSONArray(GAME_LIST_TAG);
			for (int i = 0; i < games.length(); i++) {
				JSONObject game = games.getJSONObject(i);
				long gameId = game.getLong(GAME_ID_TAG);
				String location = game.getString(GAME_LOCATION_TAG);
				int numberOfUsers = game.getInt(GAME_NUMBER_OF_USERS_TAG);
				Calendar endDate = Calendar.getInstance();
				endDate.setTimeInMillis(game.getLong(GAME_END_DATE_TAG) * 1000);
				result.add(new Game(gameId, location, numberOfUsers, endDate));
			}
		} catch (JSONException e) {
			return result;
		}
		return result;
	}

	/**
	 * Parses a notification list in JSON format.
	 * 
	 * @param notificationList
	 *            Notification list in JSON format.
	 * @return {@link Notification} list.
	 */
	public static List<Notification> parseNotificationList(
			String notificationList) {
		List<Notification> result = new LinkedList<Notification>();
		try {
			JSONObject json = new JSONObject(notificationList);
			JSONArray notifications = json.getJSONArray(NOTIFICATIONS_TAG);
			for (int i = 0; i < notifications.length(); i++) {
				JSONObject notification = notifications.getJSONObject(i);
				String userName = notification.getString(USER_NAME_TAG);
				int currentStep = notification.getInt(CURRENT_STEP_TAG);
				int score = notification.getInt(CURRENT_SCORE_TAG);
				result.add(new Notification(userName, currentStep, score));
			}
		} catch (JSONException e) {
			return result;
		}
		return result;
	}

	/**
	 * Parses a game status in JSON format.
	 * 
	 * @param gameStatusJson
	 *            Game status in JSON format.
	 * @return A {@link GameGlobalStatus} object.
	 */
	public static GameGlobalStatus parseGameStatus(String gameStatusJson) {
		GameGlobalStatus result = null;
		try {
			JSONObject gameStatus = new JSONObject(gameStatusJson);
			long gameId = gameStatus.getLong(GAME_ID_TAG);
			long globalMaxStep = gameStatus.getLong(GAME_MAX_STEP_TAG);
			JSONArray usersData = gameStatus
					.getJSONArray(GAME_USERS_STATUS_TAG);
			List<GameUserData> userData = new LinkedList<GameUserData>();
			for (int i = 0; i < usersData.length(); i++) {
				JSONObject userStatusJson = usersData.getJSONObject(i);
				String userName = userStatusJson.getString(USER_NAME_TAG);
				int currentStep = userStatusJson.getInt(CURRENT_STEP_TAG);
				int score = userStatusJson.getInt(CURRENT_SCORE_TAG);
				userData.add(new GameUserData(userName, currentStep, score));
			}
			result = new GameGlobalStatus(gameId, userData, globalMaxStep);
		} catch (JSONException e) {
			return result;
		}
		return result;
	}

	/**
	 * 
	 * @param password
	 * @return
	 */
	public static String hashPassword(String password) {
		MessageDigest mDigest;
		try {
			mDigest = MessageDigest.getInstance(HASH_ALGORITHM);
		} catch (NoSuchAlgorithmException e) {
			return "";
		}
		byte[] result = mDigest.digest(password.getBytes());
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < result.length; i++) {
			sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16)
					.substring(1));
		}

		return sb.toString();
	}

	// TODO comment
	public static SharedPreferences getPreferences(Context context) {
		return context.getSharedPreferences(
				context.getString(R.string.const_string_preferences),
				Activity.MODE_PRIVATE);
	}

	public static List<GameUserData> parseScores(String userName,
			String response) {
		List<GameUserData> scores = new LinkedList<GameUserData>();
		try {
			JSONObject scoresJson = new JSONObject(response);
			int userScore = scoresJson.getInt(USER_SCORE_TAG);
			scores.add(new GameUserData(userName, 0, userScore));
			JSONArray usersData = scoresJson.getJSONArray(HIGH_SCORES_TAG);
			for (int i = 0; i < usersData.length(); i++) {
				JSONObject userStatusJson = usersData.getJSONObject(i);
				String rivalName = userStatusJson.getString(USER_NAME_TAG);
				int score = userStatusJson.getInt(CURRENT_SCORE_TAG);
				scores.add(new GameUserData(rivalName, 0, score));
			}
			return scores;
		} catch (JSONException e) {
			return null;
		}
	}

	public static List<String> parseClues(String clueString) {
		List<String> clues = new LinkedList<String>();
		try {
			JSONArray cluesJson = new JSONObject(clueString).getJSONArray("hints");
			for (int i = 0; i < cluesJson.length(); i++) {
				// TODO parameter
				clues.add(cluesJson.getJSONObject(i).getString("hint_text"));
			}
			Collections.reverse(clues);
			return clues;
		} catch (JSONException e) {
			return clues;
		}
	}
}